﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using BGSpaceShooterServer;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace BGSpaceShooter
{
    public class GameObjectFactory
    {

        private Dictionary<GameObjectName, GameObject> LoadedModels;

        public GameObjectFactory()
        {
            LoadedModels = new Dictionary<GameObjectName, GameObject>();
        }

        private void PrepareModel(GameObject gameObject)
        {
            foreach (ModelMesh modelMesh in gameObject.Model.Meshes)
            {
                foreach (BasicEffect effect in modelMesh.Effects)
                {
                    gameObject.Textures.Add(effect.Texture);
                    gameObject.DiffuseColor.Add(effect.DiffuseColor);
                    gameObject.Specular.Add(effect.SpecularColor);
                    gameObject.SpecularFactor.Add(effect.SpecularPower);
                    gameObject.Ambient.Add(0.4f);

                }
            }

            foreach (ModelMesh modelMesh in gameObject.Model.Meshes)
            {
                foreach (ModelMeshPart modelMeshPart in modelMesh.MeshParts)
                {
                    modelMeshPart.Effect = TechniqueProvider.GetEffect("TexturedShaded").Clone();
                }
            }

            foreach (ModelMesh modelMesh in gameObject.Model.Meshes)
            {
                foreach (Effect effect in modelMesh.Effects)
                {
                    effect.CurrentTechnique = effect.Techniques["TexturedShaded"];
                }
            }
        }

        private StarFighter PrepareStarFighterInstance(GameObjectName gameObjectName)
        {
            GameObject loadedFighter = LoadedModels[gameObjectName];
            StarFighter preparedFighter = new StarFighter(loadedFighter.Model);

            preparedFighter.Textures.AddRange(loadedFighter.Textures);
            preparedFighter.DiffuseColor.AddRange(loadedFighter.DiffuseColor);
            preparedFighter.Specular.AddRange(loadedFighter.Specular);
            preparedFighter.SpecularFactor.AddRange(loadedFighter.SpecularFactor);
            preparedFighter.Ambient.AddRange(loadedFighter.Ambient);

            foreach (ModelMesh modelMesh in preparedFighter.Model.Meshes)
            {
                foreach (ModelMeshPart modelMeshPart in modelMesh.MeshParts)
                {
                    modelMeshPart.Effect = TechniqueProvider.GetEffect("TexturedShaded").Clone();
                }
            }

            foreach (ModelMesh modelMesh in preparedFighter.Model.Meshes)
            {
                foreach (Effect effect in modelMesh.Effects)
                {
                    effect.CurrentTechnique = effect.Techniques["TexturedShaded"];
                }
            }

            return preparedFighter;
        }

        public Projectile PrepareProjectileInstance(GameObjectName gameObjectName)
        {
            GameObject loadedFighter = LoadedModels[gameObjectName];
            Projectile projectile = new Projectile(LoadedModels[gameObjectName].Model);

            projectile.Textures.AddRange(loadedFighter.Textures);
            projectile.DiffuseColor.AddRange(loadedFighter.DiffuseColor);
            projectile.Specular.AddRange(loadedFighter.Specular);
            projectile.SpecularFactor.AddRange(loadedFighter.SpecularFactor);
            projectile.Ambient.AddRange(loadedFighter.Ambient);

            foreach (ModelMesh modelMesh in projectile.Model.Meshes)
            {
                foreach (ModelMeshPart modelMeshPart in modelMesh.MeshParts)
                {
                    modelMeshPart.Effect = TechniqueProvider.GetEffect("TexturedShaded").Clone();
                }
            }

            foreach (ModelMesh modelMesh in projectile.Model.Meshes)
            {
                foreach (Effect effect in modelMesh.Effects)
                {
                    effect.CurrentTechnique = effect.Techniques["TexturedShaded"];
                }
            }

            return projectile;
        }

        public Projectile CreateProjectile(GameObjectName gameObjectName)
        {
            if (!LoadedModels.ContainsKey(gameObjectName))
            {
                Model model = GameContentManager.Content.GetModel(gameObjectName);
                Projectile loadedProjectile = new Projectile(model);
                PrepareModel(loadedProjectile);

                LoadedModels.Add(gameObjectName, loadedProjectile);
            }

            Projectile projectile = PrepareProjectileInstance(gameObjectName);
            projectile.Position = new Vector3(0, 0, 0);

            if (gameObjectName == GameObjectName.Bullet) //HACK DLA ROZMIARU ASTEROIDY!!!! //TODO zmienic model
                projectile.Scale = BGSpaceShooterServer.Server.BulletBoundingSphereRadius / projectile.BoundingSphere.Radius;
            return projectile;

        }

        public StarFighter CreateStarFighter()
        {
            if (!LoadedModels.ContainsKey(GameObjectName.Viper))
            {
                Model model = GameContentManager.Content.GetModel(GameObjectName.Viper);
                StarFighter loadedFighter = new StarFighter(model);
                PrepareModel(loadedFighter);

                LoadedModels.Add(GameObjectName.Viper, loadedFighter);
            }
            StarFighter starFighter = PrepareStarFighterInstance(GameObjectName.Viper);
            starFighter.Position = new Vector3(0);
            ReadStats(starFighter, GameObjectName.Viper);
            return starFighter;
        }

        private void ReadStats(StarFighter starFighter, GameObjectName starFighterType)
        {
            XDocument document = XDocument.Load(".\\Content\\Resources\\StarFighterStats.xml");

            XElement element =
                document.Elements().Where(s => s.Attribute("Name").Value == starFighterType.ToString()).First();

            starFighter.ModelID = Int32.Parse(element.Attribute("ID").Value);
            starFighter.MaxHP = Int32.Parse(element.Attribute("HP").Value);
            starFighter.HP = starFighter.MaxHP;
            starFighter.MaxVelocity = new Vector3(float.Parse(element.Attribute("VelocityX").Value),
                                                  float.Parse(element.Attribute("VelocityY").Value),
                                                  float.Parse(element.Attribute("VelocityZ").Value));
            starFighter.Acceleration = new Vector3(float.Parse(element.Attribute("AccelerationX").Value),
                                                   float.Parse(element.Attribute("AccelerationY").Value),
                                                   float.Parse(element.Attribute("AccelerationZ").Value));
            foreach (StarFighterComponent starFighterComponent in starFighter.StarFighterComponents)
            {
                XElement component = element.Elements().Where(s => s.Value == starFighterComponent.MeshName).First();

                starFighterComponent.MaxHP = Int32.Parse(component.Attribute("HP").Value);
                starFighterComponent.HP = starFighterComponent.MaxHP;
                starFighterComponent.ID = Int32.Parse(component.Attribute("ID").Value);
            }
        }
    }
}
